package com.flea.service;

import com.flea.exception.ServiceException;
import com.flea.model.Order;
import com.flea.model.Product;
import com.flea.model.User;
import com.flea.model.shoppigcart.ShoppingCart;
import com.flea.repository.jdbc.OrderRepository;
import com.flea.repository.jdbc.ProductRepository;
import com.flea.repository.jdbc.UserRepository;
import com.flea.web.websocket.MessageCountWebSocketHandler;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import java.util.Objects;

@Service
public class OrderService {
    @Resource
    private OrderRepository orderRepository;

    @Resource
    private ProductRepository productRepository;

    @Resource
    private UserRepository userRepository;

    @Resource
    private MessageCountWebSocketHandler menuCountWebSocketHandler;

    /**
     * 结账
     *
     * @param shoppingCart
     * @return
     */
    public Order checkout(ShoppingCart shoppingCart) {
        return null;
    }

    /**
     * 购买产品
     * 1. 必须开启事务
     * 2. 正确的扣减库存，预防超卖
     * 3. 组装订单
     * 4. WebSocket 通知卖家
     *
     * @param buyerId   Who
     * @param productId What
     * @param quantity  How many
     * @return
     */
    @Transactional
    public Order buy(Integer buyerId, Integer productId, short quantity) {
        // 购买数量>0
        if (quantity < 1) {
            throw new ServiceException("购买数量必须");
        }
        Product product = productRepository.findById(productId).orElseThrow(() -> new ServiceException("您购买的产品不存在"));
        // 不能购买自己的产品
        if (Objects.equals(buyerId, product.getUserId())) {
            throw new ServiceException("您无法购买自己发布的产品");
        }
        // 购买的数量不能超过库存
        if (quantity > product.getInventory()) {
            throw new ServiceException("库存不足");
        }

        //
        // 减库存
        long n = productRepository.decInventory(productId, quantity, product.getInventory());

        if (n == 0) {
            boolean buySuccess = false;
            int count = 1;
            while (count <= 3) {
                product = productRepository.findById(productId).get();
                n = productRepository.decInventory(productId, quantity, product.getInventory());
                if (n == 1) {
                    buySuccess = true;
                    break;
                }
                count++;
            }

            if (!buySuccess) {
                throw new ServiceException("购买失败，请重试");
            }
        }


        // 计算总价
        BigDecimal totalAmount = product.getCurrentPrice().multiply(BigDecimal.valueOf(quantity));

//        if (totalAmount.doubleValue() > 0) {
//            throw new ServiceException("测试一次，模拟事务是否回滚");
//        }

        // 创建订单
        Order order = new Order();
        order.setBuyerId(buyerId);
        order.setTotalAmount(totalAmount);
        order.setSellerId(product.getUserId());
        order.setShippingFee(product.getShippingFee());
        order.setShippingAddress("这里的地址我暂时写死");
        order.setCreateTime(Instant.now());
        order.setUpdateTime(Instant.now());
        order.createOrderItem(product, quantity);

        order = orderRepository.save(order);
        order = orderRepository.findById(order.getId()).get();

        // 通知卖家
        User buyer = userRepository.findById(buyerId).get();
        String message = String.format("%s购买了你发布的%s", buyer.getNickname(), product.getName());
        menuCountWebSocketHandler.sendMessage(product.getUserId(), message);

        return order;
    }

    public Page<Order> findByBuyer(Integer userId, Pageable pageable) {
        List<Order> list = orderRepository.findByBuyerId(userId, pageable);
        long total = orderRepository.countByBuyerId(userId);
        return PageableExecutionUtils.getPage(list, pageable, () -> total);
    }

    public Page<Order> findBySeller(Integer userId, Pageable pageable) {
        List<Order> list = orderRepository.findBySellerId(userId, pageable);
        long total = orderRepository.countBySellerId(userId);
        return PageableExecutionUtils.getPage(list, pageable, () -> total);
    }
}
